#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>

#include "log.h"
#include "cmd_trie.h"
#include "login.h"

#define ARGS_CHECK(argc,expect){if(argc!=expect){printf("argc num is wrong.\n");exit(-1);}}

#define CMD_MAX 20
#define ARG_MAX 100
#define CMD_LINE_MAX 1024
/* #define DEBUG */

uint8_t success_code=100;
void *callback_login(tlv_t *tlv,int sockfd,uint8_t type,uint32_t length,const uint8_t *value,void *args){
    if(type==RESPONSE){
        if(memcmp(value,&success_code,length)==0){
            *(int*)args=1;
        }
    }
    return NULL;
}

int main(int argc, char *argv[])
{
    // ./client 192.168.159.128 12345
    ARGS_CHECK(argc,3);

    char error_str[1024];
    openlog("netdisk_client",LOG_PID|LOG_CONS,LOG_USER);

    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr;
    addr.sin_family=AF_INET;
    addr.sin_addr.s_addr=inet_addr(argv[1]);
    addr.sin_port=htons(atoi(argv[2]));
    if(connect(sockfd,(struct sockaddr*)&addr,sizeof(addr))==-1){
        strerror_r(errno,error_str,sizeof(error_str));
        LOG(LOG_ERR,error_str);
        return -1;
    }

    tlv_t tlv;
    int certified=0;
    while(!certified){
        if(login_handler(&tlv,sockfd,callback_login,&certified)==-1){
            close(sockfd);
            return -1;
        }
        LOG(LOG_INFO,"logining");
    }
    /*
     * cd path
     * ls path
     * pwd
     * mkdir dir_name
     * rmdir dir_name
     * puts file_name
     * gets file_name
     * remove file_name
     */
    trie_t cmd_dict;
    init_func(&cmd_dict);
    cmd_func_ptr_t exit_cmd_func=trie_get_func(&cmd_dict,"exit");
    cmd_func_ptr_t pwd_cmd_func=trie_get_func(&cmd_dict,"pwd");

    char cmd[CMD_MAX],arg[ARG_MAX],cmd_line[CMD_LINE_MAX];

    long exit_flag=0;
    while(!exit_flag){
        if(pwd_cmd_func){
            pwd_cmd_func(&tlv,sockfd,"");
            printf("$:");fflush(stdout);
            LOG(LOG_INFO,"pwd");
        }

        if(fgets(cmd_line,sizeof(cmd_line),stdin)==NULL){
            if(exit_cmd_func){
                exit_cmd_func(&tlv,sockfd,"");
                printf("\n");
            }
            break;
        }
        cmd[0]='\0',arg[0]='\0';
        sscanf(cmd_line,"%s %s",cmd,arg);
#ifdef DEBUG
        printf("cmd=%s\narg=%s\n",cmd,arg);
#endif
        cmd_func_ptr_t func=trie_get_func(&cmd_dict,cmd);
        if(func!=NULL){
            exit_flag=(long)func(&tlv,sockfd,arg);
            printf("\n");
            LOG(LOG_INFO,cmd_line);
        }else{
            printf("Invalid Command.\n");
        }
    }
    close(sockfd);
    closelog();
    return 0;
}
